<script setup lang="ts">
import {DataBoard, Monitor, Upload} from "@element-plus/icons-vue";
import {defineProps, onUnmounted, ref} from "vue";
import {useBaseStore} from "@/stores/base.ts";
import {ElMessage} from "element-plus";

const props = defineProps({
  wsSendMessage: {
    type: Function,
    required: true
  }
})

const baseStore = useBaseStore()

const sdp = ref("")
const ice = ref("")
const remoteVideo = ref<HTMLVideoElement>();
let dataChannel: RTCDataChannel | undefined = undefined
let peerConnection: RTCPeerConnection | null = null;

const clickJoinRoom= async ()=>{
  if ( !baseStore.rtcSession.status.wsStatus ){
    ElMessage.warning("ws未连接，无法开启共享操作，请联系管理员！")
    return
  }
  await initPeerConn()
  props.wsSendMessage({type:"register",content: baseStore.rtcSession.roomId +"_answer"})
  props.wsSendMessage({type:"getSignal",content: JSON.stringify([baseStore.rtcSession.roomId,"offer"])})
  startEvnListening()
  baseStore.rtcSession.status.connDescription="会话持续中..."
  baseStore.rtcSession.status.sharing = true
}
const initAnswer = async (content:string)=>{
  let params = null
  try {
    params = JSON.parse(content)
  }catch (e){
    ElMessage.warning("房间号不正确，无法获取到预期内的P2P连接信息！"+e)
    return
  }
  const offer = JSON.parse(params[0])
  peerConnection?.setRemoteDescription( new RTCSessionDescription( offer ) )
  const answer= await peerConnection?.createAnswer()
  sdp.value = JSON.stringify(answer)
  peerConnection?.setLocalDescription(answer)
  // 添加ICE
  const candidate = JSON.parse(params[1]);
  await peerConnection?.addIceCandidate(new RTCIceCandidate(candidate));
  // 开始ice收集
  await new Promise<void>( (resolve)=>{
    if (peerConnection?.iceGatheringState === 'complete') {
      resolve();
      return;
    }
    const onIceCandidate = (event: RTCPeerConnectionIceEvent) => {
      if (!event.candidate) {
        peerConnection?.removeEventListener('icecandidate', onIceCandidate);
        resolve();
      }
    };
    peerConnection?.addEventListener('icecandidate', onIceCandidate);
    setTimeout(() => {
      peerConnection?.removeEventListener('icecandidate', onIceCandidate);
      resolve();
    }, 500);
  } )
}
const initPeerConn = async ()=>{
  const configuration: RTCConfiguration = {
    iceServers: [],
  };
  peerConnection = new RTCPeerConnection(configuration);
  // ICE candidate 收集
  peerConnection.onicecandidate = (event) => {
    if (event.candidate) {
      ice.value = JSON.stringify(event.candidate)
      // 收集完毕后发送信令信息
      props.wsSendMessage({type:"sayHi",content:JSON.stringify([sdp.value,ice.value,"answer",baseStore.rtcSession.roomId])})
    }
  };
  // 远程流到达
  peerConnection.ontrack = (event) => {
    if (remoteVideo.value && event.streams && event.streams[0]) {
      remoteVideo.value.srcObject = event.streams[0];
    }
  };
  // 连接状态变化
  peerConnection.oniceconnectionstatechange = () => {
    if (peerConnection) {
      const state = peerConnection.iceConnectionState;
      console.log("peer conn 状态变化",state)
    }
  }
  createDataChannel()
}
const createDataChannel = ()=>{
  if (dataChannel) return
  peerConnection!.ondatachannel = (event)=>{
    console.log(event)
    dataChannel = event.channel
    dataChannel!.onopen = ()=>{
      console.log('DataChannel 已打开')
    }
    dataChannel!.onmessage = (event)=>{
      console.log('DataChannel 收到消息：',event.data)
    }
    dataChannel!.onclose  = ()=>{
      console.log('DataChannel 已关闭：')
    }
  }
}

const isRemoteControl = ref(false) // 开启远程控制

const sendCommand = (data:any)=>{
  if ( isRemoteControl.value ){
    dataChannel?.send( JSON.stringify(data))
  }
}

const handleMouseMove = (event:any)=>{
  // 获取相对于video元素的坐标
  const {x,y,w,h} = getRelativeCoords(event);
  sendCommand({type:"mouse",x:Math.ceil(x*w),y:Math.ceil(y*h)})
}
const handleKeyDown = (event:any)=>{
  console.log("键盘按下",event.key,event.code)
  sendCommand({type:"keyDown",key:event.key,code:event.code})
}
const handleClick = (event:any)=>{
  console.log('单击事件', event)
  sendCommand({type:"click"})
}
const handleDoubleClick = (event:any) => {
  console.log('双击事件', event)
  sendCommand({type:"doubleClick"})
}
const handleRightClick = (event:any) => {
  event.preventDefault() // 阻止浏览器默认右键菜单
  sendCommand({type:"rightClick"})
}
const startEvnListening = ()=>{
  if ( !isRemoteControl.value ){
    window.addEventListener('keydown', handleKeyDown);
    console.log("开始事件监听")
  }
}
const stopListening = ()=>{
  if ( isRemoteControl.value ){
    window.addEventListener('keydown', handleKeyDown);
    isRemoteControl.value = false;
    console.log("停止事件监听")
  }
}
// 使用鼠标相对于 video 元素的相对位置。这样更加精确，可以忽略因为内外边距等便宜效果形成的误差
const getRelativeCoords =(event:any)=> {
  if (!remoteVideo.value) {
    ElMessage.error("Video element is not available")
    console.error('Video element is not available');
    return {x:0,y:0,w:0,h:0};
  }
  const rect = remoteVideo.value.getBoundingClientRect();
  // 计算相对于video元素的坐标
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  return { x, y,w:(remoteVideo.value.videoWidth/rect.width),h:(remoteVideo.value.videoHeight/rect.height) };
}

onUnmounted( ()=>{
  stopListening()
} )
defineExpose({
  initAnswer
})

</script>

<template>
  <div class="h-full">
    <!--      创建房间-->
    <div class="flex flex-col items-center gap-4 ">
      <div class="flex w-2/5 justify-center">
        <el-input v-model="baseStore.rtcSession.roomId" placeholder="请输入房间号" size="large" v-show="!baseStore.rtcSession.status.sharing"></el-input>
      </div>
      <div class="flex" v-show="!baseStore.rtcSession.status.sharing">
        <el-button type="primary" :icon="Upload" size="large" @click="clickJoinRoom" :disabled="baseStore.rtcSession.roomId==''  ">加入房间</el-button>
      </div>
      <div class="flex justify-center items-center" v-show="baseStore.rtcSession.status.sharing">
        <el-icon size="26" color="green" class="mr2"><Monitor /></el-icon>共享中
        <el-button :icon="DataBoard" type="danger" size="large" class="mr2" @click="isRemoteControl=!isRemoteControl">停止远程</el-button>
        <el-button :icon="DataBoard" type="danger" size="large" class="mr2">断开连接</el-button>
      </div>
    </div>
    <el-divider />
    <div class="inline-flex items-center justify-center w-12 h-12 rounded-lg bg-green-500">
      <el-icon size="20" color="white" ><Monitor /></el-icon>
    </div>
    <div class="inline-block ml-2">
      <div>
        <p class="font-bold">房间信息</p>
      </div>
      <div>
        <el-text>
          远程控制状态：
          <el-text type="success" v-show="isRemoteControl">是</el-text>
          <el-text type="info" v-show="!isRemoteControl">否</el-text>
        </el-text>
      </div>
    </div>
    <video ref="remoteVideo" autoplay playsinline
           @mousemove="handleMouseMove"
           @click="handleClick"
           @dblclick="handleDoubleClick"
           @contextmenu="handleRightClick"
    >
    </video>
  </div>
</template>

<style scoped lang="scss">

</style>
